
#include "stdafx.h"
#include "interface.h"


#include <winioctl.h>
//#include <stdio.h>
#include <stdlib.h>
//#include <string.h>
//#include <memory.h>
//#include <ctype.h>
//#include <malloc.h>

//#include <winerror.h>
//#include <winsock.h>

#include <ntddndis.h>
#include "drvuser.h"
#include "ndis_structures.h"


//***********************************
HANDLE OpenHandle(CHAR   *pDeviceName);
ULONG EnumerateDevices(HANDLE  , PNDISTUNER_ADAPTER_INF , DWORD );
int OpenNdisDevice(HANDLE  Handle, WCHAR* pDeviceName, int len);
int DoQueryOid (HANDLE Handle, NDIS_OID Oid, DWORD BufferSize, LPVOID pBuffer);
void AcquireStats(HANDLE Handle, PNDISTUNER_GEN_STATS pGenStats);
void AcquireGenChars(HANDLE Handle, PNDISTUNER_GEN_CHARS pGenStats);
void AcquireEthStats(HANDLE Handle, PNDISTUNER_ETH_STATS pGenStats);
void AcquireEthChars(HANDLE Handle, PNDISTUNER_ETH_CHARS pGenStats);
int StartDriver();

extern "C" __declspec(dllexport) int Get(int comID, void* p,
								 int &mem, HANDLE adapterDrvr)
{
  DWORD i = 0;
  PNDISTUNER_ADAPTER_INF pAdapter;
	if (p == 0)
    return BAD_POINTER;
	switch (comID)
	{
	case GET_ADAPTERS:
		if (mem<=0)
      return BAD_POINTER;
		HANDLE DeviceHandle;
		if (!StartDriver())
      return ERROR_IN_DRIVER;
		DeviceHandle = OpenHandle("\\\\.\\\\NdisProt");
		if (DeviceHandle == INVALID_HANDLE_VALUE) 
      return CANNT_OPEN_DRIVER;
		ULONG a;
		pAdapter = (PNDISTUNER_ADAPTER_INF) p;
		i = 0;
		do 
		{
			a = EnumerateDevices(DeviceHandle, pAdapter, i);
			pAdapter++;
			i++;
		}while ((a == 0) && (i < mem));

		CloseHandle(DeviceHandle);
		if ((a != ERROR_NO_MORE_ITEMS) && (a != 0))
      return ERROR_IN_DRIVER;
		if (a==ERROR_NO_MORE_ITEMS) 
      i--;
		if (i==mem) 
      return (NOT_ENOUGH_MEMORY);
		mem = i;
		return 0;
		
	case GET_GEN_STATISTICS:
		AcquireStats(adapterDrvr, (PNDISTUNER_GEN_STATS) p);
		return 0;

	case GET_GEN_CHARS:
		AcquireGenChars(adapterDrvr, (PNDISTUNER_GEN_CHARS) p);
    return 0;

	case GET_ETH_STATISTICS:
		AcquireEthStats(adapterDrvr, (PNDISTUNER_ETH_STATS) p);
		return 0;

	case GET_ETH_CHARS:
		AcquireEthChars(adapterDrvr, (PNDISTUNER_ETH_CHARS) p);
		return 0;

	default:
		return INVALID_COMMAND;
	}

	return 0;
}

extern "C" __declspec(dllexport) int Set(int comID, void* p, 
								 int mem, HANDLE& adapterDrvr)
{
  WCHAR* guid;
	if ((p == 0) || (mem <= 0))
    return BAD_POINTER;
	switch (comID)
	{
	case SET_ADAPTER:
    HANDLE DeviceHandle;
		DeviceHandle = OpenHandle("\\\\.\\\\NdisProt");
		if (DeviceHandle == INVALID_HANDLE_VALUE)
      return CANNT_OPEN_DRIVER;
    guid = (WCHAR*) p;
		if (!OpenNdisDevice(DeviceHandle, guid, mem)) 
      return ERROR_IN_DRIVER;
		else adapterDrvr = DeviceHandle;
		return 0;
		break;

	default:
		return INVALID_COMMAND;
	}
	
	return 0;
}

int StartDriver()
{
	STARTUPINFO si;
	si.cb = sizeof(STARTUPINFO);
	si.lpReserved = 0;
	si.lpDesktop = 0;
	si.lpTitle = 0;
	si.cbReserved2 = 0;
	si.lpReserved2 = 0;
	si.dwFlags = STARTF_USESHOWWINDOW;
	si.wShowWindow = SW_HIDE;
	PROCESS_INFORMATION pi;
	if (CreateProcess(NULL, "net start ndisprot",
		NULL, NULL, FALSE, 0,
		NULL, NULL, &si, &pi))
	{
		DWORD status;
		do GetExitCodeProcess(pi.hProcess, &status);
		while (status == STILL_ACTIVE);
		CloseHandle(pi.hThread);
		CloseHandle(pi.hProcess);
		return 1;
	}
	return 0;
}

HANDLE
OpenHandle(
    CHAR    *pDeviceName
)
{
    DWORD   DesiredAccess;
    DWORD   ShareMode;
    LPSECURITY_ATTRIBUTES   lpSecurityAttributes = NULL;

    DWORD   CreationDistribution;
    DWORD   FlagsAndAttributes;
    HANDLE  TemplateFile;
    HANDLE  Handle;
    DWORD   BytesReturned;

    DesiredAccess = GENERIC_READ|GENERIC_WRITE;
    ShareMode = 0;
    CreationDistribution = OPEN_EXISTING;
    FlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
    //TemplateFile = (HANDLE)INVALID_HANDLE_VALUE;

    Handle = CreateFile(
                pDeviceName,
                DesiredAccess,
                ShareMode,
                lpSecurityAttributes,
                CreationDistribution,
                FlagsAndAttributes,
                NULL
            );
    if (Handle == INVALID_HANDLE_VALUE)    return Handle;
    
    //
    //  Wait for the driver to finish binding.
    //
    if (!DeviceIoControl(
                Handle,
                IOCTL_NDISPROT_BIND_WAIT,
                NULL,
                0,
                NULL,
                0,
                &BytesReturned,
                NULL))
    {
        CloseHandle(Handle);
        Handle = INVALID_HANDLE_VALUE;
    }
	
    return (Handle);
}

ULONG EnumerateDevices(HANDLE  Handle, PNDISTUNER_ADAPTER_INF pAdapter, DWORD i)
{
    char        Buf[1024];
    DWORD       BufLength = sizeof(Buf);
    DWORD       BytesWritten;
    PNDISPROT_QUERY_BINDING pQueryBinding;
	
    pQueryBinding = (PNDISPROT_QUERY_BINDING)Buf;

    pQueryBinding->BindingIndex = i;
    if (DeviceIoControl(
                Handle,
                IOCTL_NDISPROT_QUERY_BINDING,
                pQueryBinding,
                sizeof(NDISPROT_QUERY_BINDING),
                Buf,
                BufLength,
                &BytesWritten,
                NULL))
        {
          		WCHAR* p=(WCHAR*)((PUCHAR)pQueryBinding + pQueryBinding->DeviceNameOffset);
				int j; 
				for (j = 0; (j < 64) && 
					(j<(pQueryBinding->DeviceNameLength / sizeof(WCHAR))); j++, p++)
					pAdapter->GUID[j] = *p;
				pAdapter->GUIDl = --j;

				p=(WCHAR*)((PUCHAR)pQueryBinding + pQueryBinding->DeviceDescrOffset);
				for (j = 0; (j < 199) && 
					(j<(pQueryBinding->DeviceDescrLength / sizeof(WCHAR))); j++, p++)
					pAdapter->Description[j] = *p;
				pAdapter->Descrl = --j;
				return 0;
		}
    else
    {
        ULONG   rc = GetLastError();
        return  rc;        
    }
}

BOOL OpenNdisDevice(HANDLE  Handle, WCHAR *pDeviceName, int len)
{
    DWORD   BytesReturned;
	int res;
    
    res=DeviceIoControl(Handle, IOCTL_NDISPROT_OPEN_DEVICE,
                (LPVOID)pDeviceName, len * sizeof(WCHAR),
                NULL, 0, &BytesReturned, NULL);
	DWORD er;
	if (!res)
    er = GetLastError();
	return res;
}

int DoQueryOid (HANDLE Handle, NDIS_OID Oid, DWORD BufferSize, LPVOID pBuffer)
{
	if (BufferSize == 0)
    return BAD_POINTER;
	DWORD       BytesReturned;
  int			bSuccess;
  UCHAR* QueryBuffer = (UCHAR*) calloc(BufferSize + sizeof(NDIS_OID), 1);
	PNDISPROT_QUERY_OID  pQueryOid;
	if (QueryBuffer == NULL) 
    throw "Internal error with memory";

	pQueryOid = (PNDISPROT_QUERY_OID) QueryBuffer;
	pQueryOid->Oid = Oid;

    bSuccess = DeviceIoControl(Handle, IOCTL_NDISPROT_QUERY_OID_VALUE,
                            (LPVOID) QueryBuffer, BufferSize + sizeof(NDIS_OID),
                            (LPVOID) QueryBuffer, BufferSize + sizeof(NDIS_OID),
                            &BytesReturned,                          NULL);
	BytesReturned -= sizeof(NDIS_OID);
  if (bSuccess)
	{
		memcpy(pBuffer, pQueryOid->Data, BytesReturned);
		free(QueryBuffer);
		return 0;
	}
  else 
	{
		DWORD res = GetLastError();
		free(QueryBuffer);
		if ((res == ERROR_INSUFFICIENT_BUFFER) || (res == ERROR_MORE_DATA))
      return NOT_ENOUGH_MEMORY;
    else
      return ERROR_IN_DRIVER;
	}
}

//when structure has dynamic length or if we need only the length of required space
int DoQueryOidDyn (HANDLE Handle, NDIS_OID Oid, DWORD& BufferSize, LPVOID pBuffer)
{
	DWORD       BytesReturned;
    int			bSuccess;
    UCHAR* QueryBuffer;
	DWORD bSizeTemp = 0;

	if (BufferSize == 0)
    bSizeTemp = 1024; 
  else
    bSizeTemp=BufferSize;
	QueryBuffer = (UCHAR*) calloc(bSizeTemp + sizeof(NDIS_OID), 1);
	PNDISPROT_QUERY_OID  pQueryOid;
	if (QueryBuffer == NULL)
    throw "Internal error with memory";

	pQueryOid = (PNDISPROT_QUERY_OID) QueryBuffer;
	pQueryOid->Oid = Oid;

  bSuccess = DeviceIoControl(Handle, IOCTL_NDISPROT_QUERY_OID_VALUE,
                          (LPVOID) QueryBuffer, bSizeTemp + sizeof(NDIS_OID),
                          (LPVOID) QueryBuffer, bSizeTemp + sizeof(NDIS_OID),
                          &BytesReturned,                          NULL);
	BytesReturned -= sizeof(NDIS_OID);
  if (bSuccess)
	{
		int res = NOT_ENOUGH_MEMORY;
		if (BufferSize != 0) 
		{
			memcpy(pBuffer, pQueryOid->Data, BytesReturned);
			res = 0;
		}
		free(QueryBuffer);
		BufferSize = BytesReturned;
		return res;
	}
  else 
	{
		DWORD res = GetLastError();
		free(QueryBuffer);
		if ((res == ERROR_INSUFFICIENT_BUFFER) || (res == ERROR_MORE_DATA))
      return NOT_ENOUGH_MEMORY;
    else
      return ERROR_IN_DRIVER;
	}
}

void AcquireStats(HANDLE Handle, PNDISTUNER_GEN_STATS pGenStats)
{
	int res;
	pGenStats->FieldFlags=0;

  if (res=DoQueryOid(Handle, OID_GEN_XMIT_OK, sizeof(ULONG64), (LPVOID)&pGenStats->XmitOK))
  {
    NDISTUNER_SET_FLAG(pGenStats, GEN_STATS_XMIT_OK);
		pGenStats->XmitOK = res;
  }

  if (res=DoQueryOid(Handle, OID_GEN_RCV_OK, sizeof(ULONG64), (LPVOID)&pGenStats->RcvOK))
  {
    NDISTUNER_SET_FLAG(pGenStats, GEN_STATS_RCV_OK);
		pGenStats->RcvOK = res;
  }

  if (res=DoQueryOid(Handle, OID_GEN_XMIT_ERROR, sizeof(ULONG64), (LPVOID)&pGenStats->XmitError))
  {
		NDISTUNER_SET_FLAG(pGenStats, GEN_STATS_XMIT_ERROR);
		pGenStats->XmitError = res;
	}

  if (res=DoQueryOid(Handle, OID_GEN_RCV_ERROR, sizeof(ULONG64), (LPVOID)&pGenStats->RcvError))
  {
		NDISTUNER_SET_FLAG(pGenStats, GEN_STATS_RCV_ERROR);
		pGenStats->RcvError = res;
	}

  if (res=DoQueryOid(Handle, OID_GEN_RCV_NO_BUFFER, sizeof(ULONG64), 
		(LPVOID)&pGenStats->RcvNoBuffer))
	{
		NDISTUNER_SET_FLAG(pGenStats, GEN_STATS_RCV_NO_BUFFER);
		pGenStats->RcvNoBuffer = res;
	}

  if (res=DoQueryOid(Handle, OID_GEN_DIRECTED_BYTES_XMIT, sizeof(ULONG64), 
        (LPVOID)&pGenStats->DirectedBytesXmit))
  {
		NDISTUNER_SET_FLAG(pGenStats, GEN_STATS_DIRECTED_BYTES_XMIT);
		pGenStats->DirectedBytesXmit = res;
	}

  if (res=DoQueryOid(Handle, OID_GEN_DIRECTED_FRAMES_XMIT, sizeof(ULONG64), 
      (LPVOID)&pGenStats->DirectedFramesXmit))
  {
		NDISTUNER_SET_FLAG(pGenStats, GEN_STATS_DIRECTED_FRAMES_XMIT);
		pGenStats->DirectedFramesXmit = res;
	}

  if (res=DoQueryOid(Handle, OID_GEN_MULTICAST_BYTES_XMIT, sizeof(ULONG64), 
      (LPVOID)&pGenStats->MulticastBytesXmit))
  {
		NDISTUNER_SET_FLAG(pGenStats, GEN_STATS_MULTICAST_BYTES_XMIT);
		pGenStats->MulticastBytesXmit = res;
	}

  if (res=DoQueryOid(Handle, OID_GEN_MULTICAST_FRAMES_XMIT, sizeof(ULONG64), 
      (LPVOID)&pGenStats->MulticastFramesXmit))
  {
		NDISTUNER_SET_FLAG(pGenStats, GEN_STATS_MULTICAST_FRAMES_XMIT);
		pGenStats->MulticastFramesXmit = res;
	}

  if (res=DoQueryOid(Handle, OID_GEN_BROADCAST_BYTES_XMIT, sizeof(ULONG64), 
      (LPVOID)&pGenStats->BroadcastBytesXmit))
  {
		NDISTUNER_SET_FLAG(pGenStats, GEN_STATS_BROADCAST_BYTES_XMIT);
		pGenStats->BroadcastBytesXmit = res;
	}

  if (res=DoQueryOid(Handle, OID_GEN_BROADCAST_FRAMES_XMIT, sizeof(ULONG64), 
      (LPVOID)&pGenStats->BroadcastFramesXmit))
  {
		NDISTUNER_SET_FLAG(pGenStats, GEN_STATS_BROADCAST_FRAMES_XMIT);
		pGenStats->BroadcastFramesXmit = res;
	}

  if (res=DoQueryOid(Handle, OID_GEN_DIRECTED_BYTES_RCV, sizeof(ULONG64), 
      (LPVOID)&pGenStats->DirectedBytesRcv))
  {
    NDISTUNER_SET_FLAG(pGenStats, GEN_STATS_DIRECTED_BYTES_RCV);
		pGenStats->DirectedBytesRcv = res;
	}

  if (res=DoQueryOid(Handle, OID_GEN_DIRECTED_FRAMES_RCV, sizeof(ULONG64), 
      (LPVOID)&pGenStats->DirectedFramesRcv))
  {
		NDISTUNER_SET_FLAG(pGenStats, GEN_STATS_DIRECTED_FRAMES_RCV);
		pGenStats->DirectedFramesRcv = res;
	}

  if (res=DoQueryOid(Handle, OID_GEN_MULTICAST_BYTES_RCV, sizeof(ULONG64), 
      (LPVOID)&pGenStats->MulticastBytesRcv))
  {
		NDISTUNER_SET_FLAG(pGenStats, GEN_STATS_MULTICAST_BYTES_RCV);
		pGenStats->MulticastBytesRcv = res;
	}

  if (res=DoQueryOid(Handle, OID_GEN_MULTICAST_FRAMES_RCV, sizeof(ULONG64), 
      (LPVOID)&pGenStats->MulticastFramesRcv))
  {
		NDISTUNER_SET_FLAG(pGenStats, GEN_STATS_MULTICAST_FRAMES_RCV);
		pGenStats->MulticastFramesRcv = res;
	}

  if (res=DoQueryOid(Handle, OID_GEN_BROADCAST_BYTES_RCV, sizeof(ULONG64), 
      (LPVOID)&pGenStats->BroadcastBytesRcv))
  {
		NDISTUNER_SET_FLAG(pGenStats, GEN_STATS_BROADCAST_BYTES_RCV);
		pGenStats->BroadcastBytesRcv = res;
	}

  if (res=DoQueryOid(Handle, OID_GEN_BROADCAST_FRAMES_RCV, sizeof(ULONG64), 
      (LPVOID)&pGenStats->BroadcastFramesRcv))
  {
		NDISTUNER_SET_FLAG(pGenStats, GEN_STATS_BROADCAST_FRAMES_RCV);
		pGenStats->BroadcastFramesRcv = res;
	}

  if (res=DoQueryOid(Handle, OID_GEN_RCV_CRC_ERROR, sizeof(ULONG64), 
      (LPVOID)&pGenStats->RcvSrcError))
  {
    NDISTUNER_SET_FLAG(pGenStats, GEN_STATS_RCV_SRC_ERROR);
		pGenStats->RcvSrcError = res;
	}

  if (res=DoQueryOid(Handle, OID_GEN_TRANSMIT_QUEUE_LENGTH, sizeof(ULONG64), 
      (LPVOID)&pGenStats->TransmitQueueLength))
  {
		NDISTUNER_SET_FLAG(pGenStats, GEN_STATS_TRANSMIT_QUEUE_LENGTH);
		pGenStats->TransmitQueueLength = res;
	}

}

void AcquireGenChars(HANDLE Handle, PNDISTUNER_GEN_CHARS pGenStats)
{
	int res;
	pGenStats->FieldFlags=0;

	if (res=DoQueryOid(Handle, OID_GEN_VENDOR_ID, sizeof(DWORD), 
        (LPVOID)&pGenStats->VendorId))
  {
    NDISTUNER_SET_FLAG(pGenStats, GEN_CHARS_VENDOR_ID);
		pGenStats->VendorId = res;
	}

	if (res=DoQueryOid(Handle, OID_GEN_HARDWARE_STATUS, sizeof(DWORD), 
      (LPVOID)&pGenStats->HardwareStatus))
  {
    NDISTUNER_SET_FLAG(pGenStats, GEN_CHARS_HARDWARE_STATUS);
		pGenStats->HardwareStatus = res;
	}

	if (res=DoQueryOid(Handle, OID_GEN_MEDIA_CONNECT_STATUS, sizeof(DWORD), 
        (LPVOID)&pGenStats->MediaConnectStatus))
  {
    NDISTUNER_SET_FLAG(pGenStats, GEN_CHARS_MEDIA_CONNECT_STATUS);
		pGenStats->MediaConnectStatus = res;
	}

	if (res=DoQueryOid(Handle, OID_GEN_LINK_SPEED, sizeof(DWORD), 
        (LPVOID)&pGenStats->LinkSpeed))
  {
    NDISTUNER_SET_FLAG(pGenStats, GEN_CHARS_LINK_SPEED);
		pGenStats->LinkSpeed = res;
	}

	if (res=DoQueryOid(Handle, OID_GEN_MAXIMUM_FRAME_SIZE, sizeof(DWORD), 
        (LPVOID)&pGenStats->MaximumFrameSize))
  {
    NDISTUNER_SET_FLAG(pGenStats, GEN_CHARS_MAXIMUM_FRAME_SIZE);
		pGenStats->MaximumFrameSize = res;
	}

	if (res=DoQueryOid(Handle, OID_GEN_MAXIMUM_TOTAL_SIZE, sizeof(DWORD), 
        (LPVOID)&pGenStats->MaximumTotalSize))
  {
    NDISTUNER_SET_FLAG(pGenStats, GEN_CHARS_MAXIMUM_TOTAL_SIZE);
		pGenStats->MaximumTotalSize = res;
	}

	if (res=DoQueryOid(Handle, OID_GEN_PHYSICAL_MEDIUM, sizeof(DWORD), 
        (LPVOID)&pGenStats->PhysicalMedium))
  {
    NDISTUNER_SET_FLAG(pGenStats, GEN_CHARS_PHYSICAL_MEDIUM);
		pGenStats->PhysicalMedium = res;
	}

	if (res=DoQueryOid(Handle, OID_GEN_MAXIMUM_SEND_PACKETS, sizeof(DWORD), 
        (LPVOID)&pGenStats->MaximumSendPackets))
  {
		NDISTUNER_SET_FLAG(pGenStats, GEN_CHARS_MAXIMUM_SEND_PACKETS);
		pGenStats->MaximumSendPackets = res;
	}

	UCHAR* p = ((UCHAR*) pGenStats) + sizeof(NDISTUNER_GEN_CHARS);
	DWORD size = pGenStats->BufSize > sizeof(NDISTUNER_GEN_CHARS) ? 
		pGenStats->BufSize - sizeof(NDISTUNER_GEN_CHARS) : 0;
	DWORD OIDsize = size;

	if (res=DoQueryOidDyn(Handle, OID_GEN_VENDOR_DESCRIPTION, OIDsize, 
        (LPVOID) p))
  {
    NDISTUNER_SET_FLAG(pGenStats, GEN_CHARS_VENDOR_DESCRIPTION);
		pGenStats->VendorDescriptionOffset = res;
		if (res==ERROR_IN_DRIVER) 
      pGenStats->VendorDescriptionLength = 0;
		else
		{
			OIDsize = 0;
			DoQueryOidDyn(Handle, OID_GEN_VENDOR_DESCRIPTION, OIDsize, 
			  (LPVOID) p);
			pGenStats->VendorDescriptionLength = OIDsize;
			OIDsize = size;
		}
	}
	else
	{
		pGenStats->VendorDescriptionLength = OIDsize;
		pGenStats->VendorDescriptionOffset = pGenStats->BufSize - size;
		size -= OIDsize;
		p += OIDsize;
		OIDsize = size;
	}

	if (res=DoQueryOidDyn(Handle, OID_GEN_MEDIA_SUPPORTED, OIDsize, 
        (LPVOID) p))
  {
    NDISTUNER_SET_FLAG(pGenStats, GEN_CHARS_MEDIA_SUPPORTED);
		pGenStats->MediaSupportedOffset = res;
		if (res==ERROR_IN_DRIVER) 
      pGenStats->MediaSupportedLength = 0;
		else
		{//Not enough memory
			OIDsize = 0;
			DoQueryOidDyn(Handle, OID_GEN_MEDIA_SUPPORTED, OIDsize, 
			   (LPVOID) p);
			pGenStats->MediaSupportedLength = OIDsize;
			OIDsize = size;
		}
	}
	else
	{
		pGenStats->MediaSupportedLength = OIDsize;
		pGenStats->MediaSupportedOffset = pGenStats->BufSize - size;
		size -= OIDsize;
		p += OIDsize;
		OIDsize = size;
	}

	if (res = DoQueryOidDyn(Handle, OID_GEN_MEDIA_IN_USE, OIDsize, 
        (LPVOID) p))
  {
    NDISTUNER_SET_FLAG(pGenStats, GEN_CHARS_MEDIA_IN_USE);
		pGenStats->MediaInUseOffset = res;
		if (res == ERROR_IN_DRIVER)
      pGenStats->MediaInUseLength = 0;
		else
		{
			OIDsize = 0;
			DoQueryOidDyn(Handle, OID_GEN_MEDIA_IN_USE, OIDsize, 
		     (LPVOID) p);
			pGenStats->MediaInUseLength = OIDsize;
			OIDsize = size;
		}
	}
	else
	{
		pGenStats->MediaInUseLength = OIDsize;
		pGenStats->MediaInUseOffset = pGenStats->BufSize - size;
		size -= OIDsize;
		p += OIDsize;
		OIDsize = size;
	}

}

void AcquireEthStats(HANDLE Handle, PNDISTUNER_ETH_STATS pGenStats)
{
	int res;
	pGenStats->FieldFlags = 0;

  if (res=DoQueryOid(Handle, OID_802_3_RCV_ERROR_ALIGNMENT, 
		sizeof(DWORD), (LPVOID)&pGenStats->RcvErrorAlignment))
	{
    NDISTUNER_SET_FLAG(pGenStats, ETH_STATS_RCV_ERROR_ALIGNMENT);
		pGenStats->RcvErrorAlignment = res;
  }

	if (res=DoQueryOid(Handle, OID_802_3_XMIT_ONE_COLLISION, 
			sizeof(DWORD), (LPVOID)&pGenStats->XmitOneCollision))
	{
    NDISTUNER_SET_FLAG(pGenStats, ETH_STATS_XMIT_ONE_COLLISION);
		pGenStats->XmitOneCollision = res;
  }

	if (res=DoQueryOid(Handle, OID_802_3_XMIT_MORE_COLLISIONS, 
			sizeof(DWORD), (LPVOID)&pGenStats->XmitMoreCollisions))
	{
    NDISTUNER_SET_FLAG(pGenStats, ETH_STATS_XMIT_MORE_COLLISIONS);
		pGenStats->XmitMoreCollisions = res;
  }

	if (res=DoQueryOid(Handle, OID_802_3_XMIT_DEFERRED, 
			sizeof(DWORD), (LPVOID)&pGenStats->XmitDeferred))
	{
    NDISTUNER_SET_FLAG(pGenStats, ETH_STATS_XMIT_DEFERRED);
		pGenStats->XmitDeferred = res;
  }

	if (res=DoQueryOid(Handle, OID_802_3_XMIT_MAX_COLLISIONS, 
			sizeof(DWORD), (LPVOID)&pGenStats->XmitMaxCollisions))
	{
    NDISTUNER_SET_FLAG(pGenStats, ETH_STATS_XMIT_MAX_COLLISIONS);
		pGenStats->XmitMaxCollisions = res;
  }

	if (res=DoQueryOid(Handle, OID_802_3_RCV_OVERRUN, 
			sizeof(DWORD), (LPVOID)&pGenStats->RcvOverrun))
	{
    NDISTUNER_SET_FLAG(pGenStats, ETH_STATS_RCV_OVERRUN);
		pGenStats->RcvOverrun = res;
  }

	if (res=DoQueryOid(Handle, OID_802_3_XMIT_UNDERRUN, 
			sizeof(DWORD), (LPVOID)&pGenStats->XmitUnderrun))
	{
    NDISTUNER_SET_FLAG(pGenStats, ETH_STATS_XMIT_UNDERRUN);
		pGenStats->XmitUnderrun = res;
  }

	if (res=DoQueryOid(Handle, OID_802_3_XMIT_HEARTBEAT_FAILURE, 
			sizeof(DWORD), (LPVOID)&pGenStats->XmitHeartbeatFailure))
	{
    NDISTUNER_SET_FLAG(pGenStats, ETH_STATS_XMIT_HEARTBEAT_FAILURE);
		pGenStats->XmitHeartbeatFailure = res;
  }

	if (res=DoQueryOid(Handle, OID_802_3_XMIT_TIMES_CRS_LOST, 
			sizeof(DWORD), (LPVOID)&pGenStats->XmitTimesCrsLost))
	{
    NDISTUNER_SET_FLAG(pGenStats, ETH_STATS_XMIT_TIMES_CRS_LOST);
		pGenStats->XmitTimesCrsLost = res;
  }

	if (res=DoQueryOid(Handle, OID_802_3_XMIT_LATE_COLLISIONS, 
			sizeof(DWORD), (LPVOID)&pGenStats->XmitLateCollisions))
	{
    NDISTUNER_SET_FLAG(pGenStats, ETH_STATS_XMIT_LATE_COLLISION);
		pGenStats->XmitLateCollisions = res;
  }
}

void AcquireEthChars(HANDLE Handle, PNDISTUNER_ETH_CHARS pGenStats)
{
	int res;
	pGenStats->FieldFlags = 0;

	if (res=DoQueryOid(Handle, OID_802_3_PERMANENT_ADDRESS, 
		6 * sizeof(UCHAR), (LPVOID)&pGenStats->PermanentAddress[0]))
	{
    NDISTUNER_SET_FLAG(pGenStats, ETH_CHARS_PERMANENT_ADDRESS);
		pGenStats->PermanentAddress[0] = (UCHAR) res;
  }

	if (res=DoQueryOid(Handle, OID_802_3_CURRENT_ADDRESS, 
		6 * sizeof(UCHAR), (LPVOID)&pGenStats->CurrentAddress[0]))
	{
    NDISTUNER_SET_FLAG(pGenStats, ETH_CHARS_CURRENT_ADDRESS);
		pGenStats->CurrentAddress[0] = (UCHAR) res;
  }

	if (res=DoQueryOid(Handle, OID_802_3_MAXIMUM_LIST_SIZE, 
			sizeof(DWORD), (LPVOID)&pGenStats->MaximumListSize))
	{
    NDISTUNER_SET_FLAG(pGenStats, ETH_CHARS_MAXIMUM_LIST_SIZE);
		pGenStats->MaximumListSize = res;
  }

	if (res=DoQueryOid(Handle, OID_802_3_MAC_OPTIONS, 
			sizeof(DWORD), (LPVOID)&pGenStats->MacOptions))
	{
    NDISTUNER_SET_FLAG(pGenStats, ETH_CHARS_MAC_OPTIONS);
		pGenStats->MacOptions = res;
  }

	//Dynamic data
	UCHAR* p = ((UCHAR*) pGenStats) + sizeof(NDISTUNER_ETH_CHARS);
	DWORD size = pGenStats->BufSize > sizeof(NDISTUNER_ETH_CHARS) ? 
		pGenStats->BufSize - sizeof(NDISTUNER_ETH_CHARS) : 0;
	DWORD OIDsize = size;

	if (res=DoQueryOidDyn(Handle, OID_802_3_MULTICAST_LIST, OIDsize, 
        (LPVOID) p))
  {
    NDISTUNER_SET_FLAG(pGenStats, ETH_CHARS_MULTICAST_LIST);
		pGenStats->MulticastListOffset = res;
		if (res == ERROR_IN_DRIVER)
      pGenStats->MulticastListLength = 0;
		else
		{
			OIDsize = 0;
			DoQueryOidDyn(Handle, OID_802_3_MULTICAST_LIST, OIDsize, 
		     (LPVOID) p);
			pGenStats->MulticastListLength = OIDsize;
			OIDsize = size;
		}
	}
	else
	{
		pGenStats->MulticastListLength = OIDsize;
		pGenStats->MulticastListOffset = pGenStats->BufSize - size;
		size -= OIDsize;
		p += OIDsize;
		OIDsize = size;
	}
}
